package com.anjie.powerproject.schedule;

import com.alibaba.fastjson.JSON;
import com.anjie.powerproject.common.ModelTypeEnum;
import com.anjie.powerproject.common.Result;
import com.anjie.powerproject.entity.*;
import com.anjie.powerproject.repository.*;
import com.anjie.powerproject.service.QLExpressService;
import com.anjie.powerproject.strategy.BaseWorkStrategy;
import com.anjie.powerproject.strategy.pojo.Strategy;
import com.anjie.powerproject.strategy.utils.DateUtils;
import com.anjie.powerproject.util.CsvData;
import com.anjie.powerproject.util.CsvUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.tomcat.util.http.fileupload.RequestContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

import static com.anjie.powerproject.common.Constants.PYTHON_DIR;

/**
 * 工况动态调节条件定时写入临时工况表的定时任务
 */
@RestController
@RequestMapping(value = "schedule/dynamic")
public class DynamicPropertySchedule {
    private static final Logger logger = LoggerFactory.getLogger(DynamicPropertySchedule.class);

    @Autowired
    DynamicPropertyRepository dynamicPropertyRepository;

    @Autowired
    DeviceRepository deviceRepository;

    @Autowired
    RelationshipRepository relationshipRepository;

    @Autowired
    RelationshipComRepository relationshipComRepository;

    @Autowired
    StrategyTempRepository strategyTempRepository;

    @Autowired
    StrategyOutputRepository strategyOutputRepository;

    @Autowired
    StationInfoRepository stationInfoRepository;

    @Autowired
    ModelRepository modelRepository;

    @Autowired
    BaseWorkStrategy baseWorkStrategy;

    @Autowired
    QLExpressService expressService;

    @RequestMapping(value = "excute")
    public Result<Void> excute() {
        try {
            scheduleTask();
            return Result.ok(null);
        } catch (Exception ex) {
            logger.error(ex.getMessage(), ex);
            return Result.error(String.format("[%s]", ex.getMessage()));
        }
    }

    private Date nextHour(Date time) {
        Calendar calendar = DateUtils.dateToCalender(time);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);

        calendar.add(Calendar.HOUR, 1);

        return calendar.getTime();
    }

    private boolean checkTime(Date time, StrategyOutput strategy) {
        if (strategy == null) {
            return false;
        }
        Date startTime = DateUtils.plusOrMinusHour(strategy.getStartTime(), -1).getTime();
        Date endTime = DateUtils.plusOrMinusHour(strategy.getEndTime(), -1).getTime();

        return DateUtils.before(time, endTime) && DateUtils.after(time, startTime);
    }

    /**
     * 定时任务  工况升级中心
     */
    private void scheduleTask() throws ParseException, IOException {
        logger.info("策略动态升级定时任务启动");

        Date now = new Date();
        // 首先获取当前正在执行的图谱id
        Integer graphId = baseWorkStrategy.getGraphIdByDate(now);

        // 获取与图谱关联的设备信息备用
        List<Device> devices = deviceRepository.findDevicesByGraphId(graphId);
        Map<Integer, Device> deviceMap = devices.stream().collect(Collectors.toMap(Device::getDeviceId, d -> d));

        // 获取与图谱关联的基础策略信息备用
        List<Relationship> rels = relationshipRepository.findRelationshipsByGraphIdEquals(graphId);
//        for (Relationship rel:rels) {
//            System.out.println(rel.toString());
//        }
        Map<Integer, Relationship> relsMap = rels.stream().collect(Collectors.toMap(Relationship::getId, r -> r));

        // 使用图谱id去查询所有关联的表达式策略
        List<DynamicProperty> properties = dynamicPropertyRepository.findByGraphIdEquals(graphId);

        // 查询当前正在运行中的工况
        String time = DateUtils.ymdFormat.format(new Date());
        List<StrategyOutput> strategyList = strategyOutputRepository.getStrategyOutputByDateAndType(time, graphId);
//        System.out.println("strategyList "+strategyList.size());
//        for (StrategyOutput strategyOutput: strategyList) {
//            System.out.println("strategyOutput "+strategyOutput.toString());
//            System.out.println(strategyOutput.getDeviceFrom() + "-" + strategyOutput.getDeviceTo());
//        }
        if (CollectionUtils.isEmpty(strategyList)) {
            return;
        }
        Map<String, StrategyOutput> strategyMap = strategyList.stream().collect(Collectors.toMap(stgy -> stgy.getDeviceFrom() + "-" + stgy.getDeviceTo(), stgy -> stgy));

        // 获取当前所选择的模型
        StationInfo stationInfo = stationInfoRepository.findStationInfoLimitFirst();
        Model model = modelRepository.getSelectedModel(stationInfo.getEnergyCode(), ModelTypeEnum.ENERGY.getCode());

/********************** ↓↓ 2.5版本改动 ↓↓ *************************/
        //只有在工作日才进行工况升级
        //获取工作日期表
        //获取该类在服务器上的绝对路径
        String DynamicPropertySchedulePath=DynamicPropertySchedule.class.getClassLoader().getResource("").getPath();
        DynamicPropertySchedulePath+="static/python/common/holiday.csv";

        String bases[] = new String[]{DynamicPropertySchedulePath, "src/main/resources/"+PYTHON_DIR+"/common/holiday.csv"};

        String fbase = "";
        for (String b : bases) {
            File file = new File(b);
            if (file.exists()) {
                fbase = b;
                break;
            }
        }
        CsvData csvData = CsvUtil.loadCsv(fbase);

        //在工作日表格（holiday.csv,路径：resources/static/python/common/holiday.csv）中找到了今天，并且今天工作，0代表工作，1代表休息
        List<List<String>> dateForm=csvData.getData();

        Date d = new Date();
        SimpleDateFormat sdf = DateUtils.ymdFormat2;
        String dateNow = sdf.format(d); //今天的年月日

        SimpleDateFormat sdf2 = new SimpleDateFormat("EEEE");//星期几的格式
        String tempWeek = sdf2.format(d);//week=周一到周日：Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday
        String week="";
        switch(tempWeek) {
            case "Monday" :
                week="1";
                break;
            case "Tuesday":
                week="2";
                break;
            case "Wednesday" :
                week="3";
                break;
            case "Thursday" :
                week="4";
                break;
            case "Friday" :
                week="5";
                break;
            case "Saturday" :
                week="6";
                break;
            case "Sunday" :
                week="7";
                break;
            default :
                week="0";
        }
/********************** ↑↑ 2.5版本改动 ↑↑ *************************/

        // 逐条去执行表达式，如果表达式符合条件，并且存在当前运行着的工况，则进行工况升级
        for (DynamicProperty property : properties) {

/********************** ↓↓ 2.5版本改动 ↓↓ *************************/
//            System.out.println(property.toString());
            boolean flag=true;//是否使用工况升级的标志位，true使用，false不使用
            //检查是否在工作日期内（除节假日外进行工况升级）
            String date=property.getDate();//工况升级使用时间：周一到周日，value为1-7；工作日、节假日，value为10、11。 1,2,3表示周一周二周3工作
            if(date.length()!=0){
                //3中情况，1、工况升级使用时间为周一到周日， 2、工作日 ， 3、节假日
                if(date.contains("10")){  //工作日使用工况升级（情况2）
                    for(int i=dateForm.size()-1;i>=0;i--){
                        if(dateForm.get(i).get(0)==dateNow && dateForm.get(i).get(1)=="1"){  //今天休息，不进行工况升级
                            flag=false;
                            break;
                        }
                    }
                }else if(date.contains("11")){//节假日日使用工况升级（情况3）
                    for(int i=dateForm.size()-1;i>=0;i--){
                        if(dateForm.get(i).get(0)==dateNow && dateForm.get(i).get(1)=="0"){  //今天是工作日，不进行工况升级
                            flag=false;
                            break;
                        }
                    }
                }else if(!date.contains(week)){ //（情况1） 今天不在使用时间范围内
                    flag=false;
                }
            }

            if(flag==false){
                continue;  //不进行工况升级
            }
/********************** ↑↑ 2.5版本改动 ↑↑ *************************/

            // 首先检查当前正在运行的工况中是否存在着符合表达式左侧的工况
//            Relationship fromRel = relsMap.get(property.getResId());
//            String fromInfo = fromRel.getDeviceFrom() + "-" + fromRel.getDeviceTo();
//
//            StrategyOutput strategy = strategyMap.get(fromInfo);
//            if (!checkTime(now, strategy)) {
//                continue;
//            }

            boolean upgrade = expressService.isUpgrade(property.getExpress());
            if (upgrade) {
                StrategyTemp strategyTemp = new StrategyTemp();
                strategyTemp.setModelVersion(model.getId());
                strategyTemp.setGraphId(graphId);
                strategyTemp.setType(1);

                // 如果策略升级条件右侧是组合策略
//                if (property.getTargetIsCom() == 1) {
                if (false) {
                    logger.info("升级到组合策略升级目前不支持");
                } else {
                    Relationship rel = relsMap.get(property.getTargetResId());
                    strategyTemp.setDeviceFrom(rel.getDeviceFrom());
                    strategyTemp.setDeviceTo(rel.getDeviceTo());

                    Device fromDevice = deviceMap.get(rel.getDeviceFrom());
                    Device toDevice = deviceMap.get(rel.getDeviceTo());
                    strategyTemp.setPower(fromDevice.getPower());

                    // 起始时间为下一个小时，结束时间需要在工况动态调节条件中设置
                    Date startTime = nextHour(now);
                    strategyTemp.setStartTime(startTime);
                    strategyTemp.setEndTime(DateUtils.plusOrMinusMinute(startTime, property.getWorkTime()).getTime());

                    String start = DateUtils.hmFormat.format(strategyTemp.getStartTime());
                    String end = DateUtils.hmFormat.format(strategyTemp.getEndTime());
                    strategyTemp.setInfo(String.format("%s~%s %s->%s", start, end, fromDevice.getDeviceName(), toDevice.getDeviceName()));

//                    logger.info("升级成功! {} -> {}", JSON.toJSONString(fromRel), JSON.toJSONString(rel));
                    logger.info("升级成功! {} -> {}", JSON.toJSONString(rel));
                }
//                System.out.println(strategyTemp.toString());
                strategyTempRepository.saveAndFlush(strategyTemp);
            }
        }
    }
}